#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>
#include <string.h>
#include <cstdlib>
#include <memory>
#include <functional>
#include <sys/types.h>
#include <sys/wait.h>
#include "nocopy.hpp"
#include "InetAddr.hpp"
#include "Common.hpp"
#include "Log.hpp"
#include "Command.hpp"
#include "ThreadPool.hpp"
using namespace LogModule;
using namespace ThreadPoolModule;

using func_tt = std::function<void()>;

class TcpServer : public NoCopy
{
public:
    TcpServer(uint16_t port) : _port(port), _isruning(false)
    {
    }
    void Init()
    {
        // 1.创建listensocket
        _listensock = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            LOG(LogLevel::FATAL) << "socket error...";
            exit(SOCKET_ERR);
        }
        LOG(LogLevel::DEBUG) << "socket success: " << _listensock;
        // 2.bind
        // struct sockaddr_in server;
        // bzero(&server, sizeof(server));
        // server.sin_addr.s_addr = INADDR_ANY;
        // server.sin_family = AF_INET;
        // server.sin_port = htons(_port);
        InetAddr server(_port);
        int n = ::bind(_listensock, CONV(&server.NetAddr()), server.GetAddrLen());
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error...";
            exit(BIND_ERR);
        }
        LOG(LogLevel::DEBUG) << "bind success";
        // 3.设置监听状态，listen
        if (::listen(_listensock, 5) < 0)
        {
            LOG(LogLevel::FATAL) << "listen error...";
            exit(LISTEN_ERR);
        }
        LOG(LogLevel::DEBUG) << "listen success";
    }
    void Start()
    {
        _isruning = true;
        while (_isruning)
        {
            // 4.获取链接，accept
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = ::accept(_listensock, CONV(&peer), &len);
            if (sockfd < 0)
            {
                LOG(LogLevel::FATAL) << "accept error...";
                continue;
            }
            InetAddr client(peer);
            LOG(LogLevel::DEBUG) << "accept success ,name: " << client.StringAddr();

            // 5.提供服务
            // Service(sockfd);
            // close(sockfd);
            // ProcessConnection(sockfd,peer);
            //ThreadConnection(sockfd, peer);
            ThreadPoolConnection(sockfd,client);
        }
    }
    void Service(int sockfd,InetAddr& peer)
    {
        char buffer[1024];
        while (true)
        {
            ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
            if (n > 0)
            {
                buffer[n] = 0;
                std::cout << "client say# " << buffer << std::endl;
                std::string echo_string = "server echo# ";
                echo_string += buffer;
                write(sockfd, echo_string.c_str(), echo_string.size());
            }
            else if (n == 0) // read 如果返回值是 0，表示读到了文件结尾(对端关闭了连接！)
            {
                LOG(LogLevel::FATAL) << peer.StringAddr() << "client quit";
                break;
            }
            else
            {
                LOG(LogLevel::FATAL)<< peer.StringAddr() << "read error...";
                break;
            }
        }
    }

    // void Service(int sockfd,InetAddr& peer)
    // {
    //     Command com;
    //     char buffer[1024];
    //     while(true)
    //     {
    //         // 1. 先读取数据
    //         // a. n>0: 读取成功
    //         // b. n<0: 读取失败
    //         // c. n==0: 对端把链接关闭了，读到了文件的结尾 --- pipe
    //         ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
    //         if (n > 0)
    //         {
    //             // buffer是一个英文单词 or 是一个命令字符串
    //             buffer[n] = 0; // 设置为C风格字符串， n<= sizeof(buffer)-1

    //             std::string echo_string = com.Execute(buffer, peer);


    //             write(sockfd, echo_string.c_str(), echo_string.size());
    //         }
    //         else if (n == 0)
    //         {
    //             LOG(LogLevel::DEBUG) << peer.StringAddr() << " 退出了...";
    //             close(sockfd);
    //             break;
    //         }
    //         else
    //         {
    //             LOG(LogLevel::DEBUG) << peer.StringAddr() << " 异常...";
    //             close(sockfd);
    //             break;
    //         }
    //     }
    // }

    class ThreadData
    {
    public:
        ThreadData(int sockfd, InetAddr &ie, TcpServer *t) : _sockfd(sockfd), _client(ie), _tsv(t)
        {
        }
        ~ThreadData()
        {
        }

        int _sockfd;
        InetAddr _client;
        TcpServer *_tsv;
    };

    //线程池版本
    void ThreadPoolConnection(int sockfd,InetAddr& peer)
    {
        ThreadPool<func_tt>::GetInstance()->Enqueue([this,sockfd,&peer](){
            this->Service(sockfd,peer);
        });
    }


    // 多线程服务
    static void *Routine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *tdv = static_cast<ThreadData *>(args);
        tdv->_tsv->Service(tdv->_sockfd,tdv->_client);
        close(tdv->_sockfd);
        delete tdv;
        return nullptr;
    }
    void ThreadConnection(int sockfd, struct sockaddr_in &peer)
    {
        InetAddr client(peer);
        pthread_t tid;
        // std::shared_ptr<ThreadData> tdsv = std::make_shared<ThreadData>(sockfd,client,this);
        ThreadData *tdv = new ThreadData(sockfd, client, this);
        pthread_create(&tid, nullptr, Routine, (void *)tdv);
    }

    // 多进程服务
    void ProcessConnection(int sockfd, struct sockaddr_in &peer)
    {
        pid_t id = fork();
        if (id < 0)
        {
            close(sockfd);
            return;
        }
        else if (id == 0)
        {
            // 子进程再去创建子进程，孙子进程
            // 子进程，子进程除了看到sockfd，能看到listensockfd吗？？
            //  我们不想让子进程访问listensock！
            close(_listensock);
            if (fork() > 0)
            {
                exit(0); // 大于0，是子进程
            }
            // 到这里是孙子进程,是孤儿进程，系统去回收
            InetAddr client(peer);
            LOG(LogLevel::DEBUG) << "process connection: " << client.StringAddr();
            Service(sockfd,client);
            close(sockfd);
            exit(0);
        }
        else
        {
            // 父进程去关闭创建的子进程
            close(sockfd);
            // 这里要等待子进程
            pid_t rid = waitpid(id, nullptr, 0);
            (void)rid;
        }
    }

    ~TcpServer()
    {
    }

private:
    uint16_t _port;
    int _listensock;
    bool _isruning;
};